/**
 * @file
 * @author dousha
 * @date 2020
 */

#ifndef MESSAGING_H
#define MESSAGING_H

#include <stdint.h>

#include "../../boilerplate/types.h"

/**
 * @defgroup MessageType 消息类型
 *
 * 0x00u 是保留的值。
 *
 * 典型的类型使用方法为：
 *
 * ```
 * MESSAGE_CATEGORY | MESSAGE_CHANNEL
 * ```
 *
 * 如系统级别的初始化消息为 `MESSAGE_SYSTEM | MESSAGE_INIT`.
 */

/**
 * @ingroup MessageType
 *
 * 系统内部消息
 */
#define MESSAGE_SYSTEM 0x80u
/**
 * @ingroup MessageType
 *
 * 驱动消息
 */
#define MESSAGE_DRIVER 0xc0u
/**
 * @ingroup MessageType
 *
 * 应用消息
 */
#define MESSAGE_APPLICATION 0x40u
/**
 * @ingroup MessageType
 *
 * 应用消息
 */
#define MESSAGE_USER 0x40u
/**
 * @ingroup MessageType
 *
 * 初始化消息
 */
#define MESSAGE_INIT 0x01u
/**
 * @ingroup MessageType
 *
 * 数据消息
 */
#define MESSAGE_DATA 0x02u

/**
 * 消息体
 */
typedef struct {
	/// 消息类型码
	uint8_t type;
	/// 消息内容大小
	uint8_t size;
	/// 消息内容
	void *body;
} MessageBlock;

/**
 * 消息回调
 */
typedef struct {
	/// 消息类型码
	uint8_t type;
	/// 消息回调函数
	void (*callback)(const MessageBlock *);
} MessageCallback;

/**
 * 消息队列
 *
 * 消息队列是一个环形队列。
 */
typedef struct {
	/// 队列长度
	uint32_t size;
	/// 写偏移
	uint32_t head;
	/// 读偏移
	uint32_t tail;
	/// 队列内容指针
	MessageBlock *queue;
} MessageQueue;

extern void message_init();

extern void message_send(const MessageBlock *);

extern void message_register(const MessageCallback *);

extern MessageQueue *message_queue_create(uint32_t);

extern void *message_queue_destroy(const MessageQueue *);

extern Result message_write(const MessageQueue *, const MessageBlock *);

extern MessageBlock *message_read(const MessageQueue *);

#endif
